﻿using System.Text.Json;
using ABBService.IDAL;
using Driverplugin;
using ABBService.DAL;
using ABBService.Models;
using Google.Protobuf;
using System.Text;
using NLog;
using static Driverplugin.DeviceStatus.Types;
using Microsoft.VisualBasic;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace IoTEdge.Grpc.Server.ABBLibs.entities;

public class DeviceModel
{
    Logger logger = LogManager.GetCurrentClassLogger();
    public DeviceMeta DeviceMeta { get; set; }
    public CancellationTokenSource TokenSource { get; set; } = new();
    /// <summary>
    /// 指定执行周期
    /// </summary>
    public int Interval { get; set; }
    /// <summary>
    ///指定超时
    /// </summary>
    public int Timeout { get; set; }
    public Action<DeviceModel, Driverplugin.Data> SendMessage { get; set; }
    public Action<DeviceModel, DeviceStatus.Types.DeviceState, string> ReportErr { get; set; }
    public IABBService ABBGet { get; set; } = null;
    Model_ABBConfiguration abbcfg = null;
    public CustomProtocolModel CustomProtocolModel { get; set; }
    public void run()
    {
        //持续报告设备状态
        _ = Task.Factory.StartNew(async (x) =>
        {
            var source = x as CancellationTokenSource;
            bool firston = false;
            do
            {
                if (!firston)
                {
                    await Task.Delay(1000);
                    firston = !firston;
                }
                else
                {
                    await Task.Delay(5000);
                }
                if (!source.Token.IsCancellationRequested)
                {
                    try
                    {
                        ReportErr?.Invoke(this, DeviceState.OnlineState, "NoErr");
                    }
                    catch (Exception)
                    {
                        break;
                    }
                }

                else
                {
                    try
                    {
                        ReportErr?.Invoke(this, DeviceState.OfflineState, "Stopped");
                    }
                    catch (Exception)
                    {
                        break;
                    }

                }
            } while (true);
        }, TokenSource);
        abbcfg = new Model_ABBConfiguration();
        abbcfg.ABBIPAddr = CustomProtocolModel.IP;
        abbcfg.ABBPort = CustomProtocolModel.Port;
        abbcfg.ABBUser = CustomProtocolModel.User;
        abbcfg.ABBPwd = CustomProtocolModel.Password;
        ABBGet = new ABBService.DAL.ABBService(abbcfg);
        _ = Task.Factory.StartNew(async (x) =>
        {
            var tok = (CancellationTokenSource)x;
            string? ctrlstate = null;
            string? errstate = null;
            Model_Joints? abbjoints = null;
            string? operationMode = null;
            Model_RapidExcution? rapidExecu = null;
            Model_TargetPoints? rbtar = null;
            List<Model_RapidTasks>? rapidtasks = null;
            Model_Servoenable? servo = null;
            string? speed = null;
            UpdateDataToIoTEdge updatedata = null;
            CustomModule cos = null;
            PropertyExtensionConfig? temp1 = null;
            while (true)
            { 
                Marshal.CleanupUnusedObjectsInCurrentContext();
                temp1 = null;
                updatedata = null;
                cos = null;
                ctrlstate = null;
                errstate = null;
                abbjoints = null;
                operationMode = null;
                rapidExecu = null;
                rbtar = null;
                rapidtasks = null;
                servo = null;
                speed = null;
                if (tok.Token.IsCancellationRequested)
                    break;
                await Task.Delay(Interval);
                try
                {
                    {
                        ctrlstate = await ABBGet.ABB_CtrlState(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        errstate = await ABBGet.ABB_ErrState(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        abbjoints = await ABBGet.ABB_Joints(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        operationMode = await ABBGet.ABB_OperationMode(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        rapidExecu = await ABBGet.ABB_RapidExcution(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        rbtar = await ABBGet.ABB_RobotTarget(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        rapidtasks = await ABBGet.ABB_RapidTasks(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        servo = await ABBGet.ABB_Servoenable(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        speed = await ABBGet.ABB_SpeedRatio(abbcfg).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                        updatedata = new UpdateDataToIoTEdge();
                        updatedata.ts = DateTimeOffset.Now.DateTime.ToString($"yyyy-MM-dd{"T"}HH:mm:ss.fff:+0800");
                        updatedata.p_id = DeviceMeta.Defination.ProductID;
                        updatedata.d_id = DeviceMeta.Defination.DeviceID;
                        cos = new CustomModule();
                        foreach (var item1 in DeviceMeta.Defination.Properties)
                        {
                            if (tok.Token.IsCancellationRequested)
                                return;
                            if (!updatedata.services.ContainsKey(item1.Service))
                                updatedata.services.Add(item1.Service, cos);
                            temp1 = JsonSerializer.Deserialize<PropertyExtensionConfig>(item1.PropertyExtensionConfig);
                            switch (temp1.Address)
                            {
                                case "1":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = "1", dataType = item1.PropertyType.ToString() });
                                    break;
                                case "2":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = errstate, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "3":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = speed, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "4":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = operationMode, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "5":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = ctrlstate, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "6":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rbtar.x, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "7":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = abbjoints.J4, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "8":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = abbjoints.J5, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "9":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = abbjoints.J6, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "10":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = abbjoints.J1, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "11":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = abbjoints.J2, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "12":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = abbjoints.J3, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "13":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rapidExecu.ctrlexecstate, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "14":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rapidExecu.cycle, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "15":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rbtar.x, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "16":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rbtar.y, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "17":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rbtar.z, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "18":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rbtar.q1, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "19":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rbtar.q2, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "20":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rbtar.q3, dataType = item1.PropertyType.ToString() });
                                    break;
                                case "21":
                                    cos.properties.Add(item1.Property, new CustomProperty() { value = rbtar.q4, dataType = item1.PropertyType.ToString() });
                                    break;
                                default:
                                    break;
                            }
                            GC.Collect();
                        }

                        if (!tok.Token.IsCancellationRequested)
                        {
                            try
                            {
                                SendMessage?.Invoke(this, new Driverplugin.Data() { Datas = ByteString.CopyFrom(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(updatedata))) });
                            }
                            catch (Exception)
                            {
                                return;
                            }
                        }
                    }
                }
                catch (Exception exp)
                {
                    ReportErr?.Invoke(this, DeviceStatus.Types.DeviceState.ErrorState, exp.Message);
                    Task.Delay(100).Wait();
                    TokenSource.Cancel();
                    return;
                }
            }
        }, TokenSource);
    }
}